package de.koller.worlders.engine.entity.mo.wphysics;

import de.koller.oceanFramework.math.Vec;
import de.koller.worlders.engine.entity.IAABB;
import de.koller.worlders.engine.entity.mo.MovingObject;
import de.koller.worlders.engine.entity.plattform.Plattform;
import de.koller.worlders.engine.entity.zone.Zone;
import de.koller.worlders.engine.tiles.MOTile;
import de.koller.worlders.engine.tiles.Tile;
import java.util.*;

public class WCollision {

	private final WPhysicsRoot proot;

	public WCollision( WPhysicsRoot proot ) {
		this.proot = proot;
	}
	
	public void updateCollision( MovingObject mo, int elapsedTime ) {
		List<IAABB> aabbs = updateAABBs( mo );
		handleCollisions( mo, aabbs );
	}

	private void handleCollisions( MovingObject mo, List<IAABB> allAABBs ) {
		List<AABBIntersection.AABBImpact> intersections = new ArrayList<>();
		
		for( IAABB aabb : allAABBs ) {
			if( aabb instanceof MOTile && ((MOTile)aabb).getMo() == mo )
				continue;
			if( mo.getMoTile() != null && aabb == mo.getMoTile().getTileEntity() )
				continue;
			
			Vec w = mo.wpTransferObj.getWishWay().newInstance();
			if( aabb instanceof MOTile ) {
				MOTile mot = (MOTile)aabb;
				w.subtract( mot.getMo().wpTransferObj.getWishWay() );
			}
			AABBIntersection.AABBImpact imp = AABBIntersection.impact( w, mo, aabb );
			if( imp != null )
				intersections.add( imp );
		}
		
		Collections.sort( intersections );
		
		float plattformTOI = 1;
		List<Plattform> plattforms = new ArrayList<>();
		Set<Zone> zones = new HashSet<>();
		
		for( AABBIntersection.AABBImpact i : intersections ) {
			Tile t = (Tile)i.staObj;
			if( t.getTileEntity() == null )
				continue;
			
			if( t.getTileEntity() instanceof Zone )
				zones.add( (Zone)t.getTileEntity() );
			
			if( t.getTileEntity() instanceof Plattform )
				if( plattforms.isEmpty() || plattformTOI == i.timeOfImpact ) {
					plattformTOI = i.timeOfImpact;
					plattforms.add( (Plattform)t.getTileEntity() );
				}
		}
		
		Vec aw = new Vec(	mo.wpTransferObj.getWishWay().getX() * plattformTOI, 
							mo.wpTransferObj.getWishWay().getY() * plattformTOI );
		mo.zoneC.step( zones );
		mo.impulse( null, aw, plattforms );
		mo.wpTransferObj.getWishWay().set( aw );
	}
	
	private List<IAABB> updateAABBs( MovingObject mo ) {
		List<IAABB> aabbs = new ArrayList<>();
		
		if( mo.getMoTile() == null )
			proot.getDynamicCollisionObj().addAllTo( aabbs );
		
		double minx = Math.min( mo.getPosition().getX(), mo.getPosition().getX() + mo.wpTransferObj.getWishWay().getX() );
		double miny = Math.min( mo.getPosition().getY(), mo.getPosition().getY() + mo.wpTransferObj.getWishWay().getY() );
		double maxx = Math.max( mo.getPosition().getX() + mo.getSize().getX(), 
								mo.getPosition().getX() + mo.getSize().getX() + mo.wpTransferObj.getWishWay().getX() );
		double maxy = Math.max( mo.getPosition().getY() + mo.getSize().getY(), 
								mo.getPosition().getY() + mo.getSize().getY() + mo.wpTransferObj.getWishWay().getY() );
		
		minx = Math.floor( minx ); miny = Math.floor( miny );
		maxx = Math.floor( maxx + 1 ); maxy = Math.floor( maxy + 1 );
		
		for( int x = (int)minx; x < (int)maxx; x++ )
			for( int y = (int)miny; y < (int)maxy; y++ ) {
				Tile t = mo.wroot.getTileMap().getTileAt( x+.1f, y+.1f ).getTile();
				if( t != null )
					aabbs.add( t );
			}
		
		return aabbs;
	}
	
}
